perm filename FILER[AP,SYS]10 blob sn#029529 filedate 1973-03-16 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00019 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00003 00002	Definitions.
C00006 00003	Storage allocations.
C00010 00004	Initialization.
C00012 00005	Read in last part of last story.
C00019 00006	Search for beginning of story.  Then collect entire story.
C00022 00007	Look for end of story.
C00024 00008	Prepare to write out newly read story.
C00028 00009	See how many (if any) old stories must be deleted to fit the new story in.
C00030 00010	Update INDEX file.
C00033 00011	Write out new story.
C00036 00012	UUCODE
C00041 00013	GETCH   NXTDG   PUT2DG
C00048 00014	DELOLD  GROW    SHRINK
C00054 00015	CHGNAM  PROCRQ
C00057 00016	INTRPT  SNDHOT
C00060 00017	CONVRT:	JRST	GETCH		0: tape feed
C00063 00018	UPPER:	JRST	GETCH		0: tape feed
C00066 00019	SETSHF  CLRSHR  SPE1-7  CKPARA
C00069 ENDMK
C⊗;
;Definitions.

	TITLE	FILER

DEBUG←←0		;DEBUG ≠ 0 inhibits expansion/reduction of core

TTY12←←1  TTY←←0  DISK←←0  ;EXACTLY ONE OF THESE SHOULD BE NON-ZERO
IFN TTY12*TTY  <TOO MANY INPUT DEVICES!!!!>
IFN TTY12*DISK <TOO MANY INPUT DEVICES!!!!>
IFN TTY  *DISK <TOO MANY INPUT DEVICES!!!!>
IFN TTY12+TTY <BUFLN←←30>
IFN DISK  <BUFLN←←200>

EXTERNAL JOBAPR,JOBCNI,JOBFF

;     ACCUMULATOR ASSIGNMENTS
FLG←←0			;AC with flags in LH and zero (for IDPBs) in RH
A←1			;temporary AC
B←2			;temporary AC
C←3			;temporary AC
SLOT←4			;pointer to the current slot in LINKS
SIZE←5			;size of new story
TXTLEN←6		;length of the text (in words) to be written out
STORY←7			;saved byte pointer to first word in buffer for new story
D←←7			;temporary AC
CHAR←←10		;current character in the current story
E←←10			;temporary AC
FST←10			;pointer to first word of area to contain new story
CNT←←11			;counter for digits in sequence nbrs and for LFs at end of story
NXT←11			;pointer to first word afterarea to contain new story
BCNT←12			;counter of bytes in buffer
BPTR←13			;byte pointer into buffer holding current story
AC1←←14			;temporary AC
AC2←←15			;temporary AC
UNDUN←14		;index of first uncatalogued story
NEW←15			;index of area for next story
OLD←16			;index of oldest story
P←17			;pdl pointer

LF←←12	CR←←15
SPECS←←4		;number of special words at front of INDEX file
XSIZE←←3		;size of the index entry for one story
MAXNBR←=500		;maximum number of stories allowed
XLEN←MAXNBR*XSIZE+SPECS	;length of INDEX file
MAXK←←=58		;maximum size of NEWS file in K
RECLMT←←MAXK*=8+1	;number of record one beyond allowable rec. in NEWS file

BLEN←←2200
LLEN←←10000
DLEN←←200
PDLEN←←20		;length of the pdl
;Storage allocations.

;LEFT HALF FLAGS
;(there are no flags defined yet.)

	LOC	41
	JSR	UUCODE
	LOC

OPDEF	UEXIT	[001000,,];minor error. just exit
OPDEF	UERROR	[002000,,];moderate error. write message in ERRORS file
OPDEF	UBIGERR	[003000,,];horrendous error. write message and wakeme in 30 minutes

NEWSF:	SIXBIT	/NEWS/	;block for LOOKUP and ENTER for NEWS file
	BLOCK	3
INDEXF:	SIXBIT	/INDEX/	;block for LOOKUP and ENTER for INDEX file
	BLOCK	3
LINKSF:	SIXBIT	/LINKS/
	BLOCK	3
DICTF:	SIXBIT	/DICT/
	BLOCK	3
ERRORF:	SIXBIT	/ERRORS/
	BLOCK	3

BUF:	BLOCK	BLEN	;buffer to hold stories
;INDEX:	BLOCK	XLEN	;these three arrays now follows the end of the program
;LINKS:	BLOCK	LLEN
;DICT:	BLOCK	DLEN
IBUF:	BLOCK	3	;buffer header for buffers holding characters from AP line
TTYBUF:	BLOCK	2*(BUFLN+3)	;the 2 input buffers for tty12 go here
INLTR:	BLOCK	=32	;block for holding letter received (from HOT)
PDLIST:	BLOCK	PDLEN	;area for stack
CMD:	IOWD	1,BUF		;dump mode command list for outputting stories
	0
XCMD:	IOWD	XLEN,INDEX	;dump mode command for reading/writing INDEX file
	0
LCMD:	IOWD	LLEN,LINKS
	0
DCMD:	IOWD	DLEN,DICT
	0
DSK17:	217		;block used for opening the dsk in mode 17 many times
	SIXBIT	/DSK/		;200 bit means take error return automatically
	0			;if DISK IS FULL or BAD RETRIEVAL
WAKEBK:
IFN DEBUG<SIXBIT /Z!/>
IFE DEBUG<SIXBIT /[-AP-]/>
	SIXBIT	/ APSYS/
	0

SWAPBK:	SIXBIT	/DSK/		;block used to start up other AP programs
	0			;program name goes here
	XWD	'DMP',14	;start up program on another job and dont set JLOG
	0			;normal starting address, normal core assignment
	SIXBIT	/ APSYS/
	SIXBIT	/ APSYS/

SPBPTR:	0
SEQNBR:	0		;seq number in binary is saved here
SAVEDG:	ASCII	/     /	;seq number in ascii is saved here with two spaces at end
BEGTIM:	0		;time beginning of story came in
SAVEWD:	0
SHIFT:	0		;flag indicating upper or lower shift characters
LNKSIN:	0		;flag indicating whether or not LINKS file has been read in
DICREC:	0		;number of the current dictionary record in core
DYING:	-1		;code sent to HOT to mean FILER is dying
WHOHOT:	BLOCK	2
EXCESS:	=71
	=35
HOTLTR:	BLOCK	2	;header block for sending hot line letters
NBRFLR:	0		;indicator of number of other jobs with filer's name
CRLF:	ASCIZ	/
/
;Initialization.

FILER:	SETZ	FLG,		;clear all flags
	MOVE	P,[IOWD PDLEN,PDLIST];initialize pdl pointer
	SETZM	BUSY
	SETZM	GODOWN
	MOVEI	A,INTRPT	;get address of interrupt level module
	MOVEM	A,JOBAPR	;store it in JOBAPR
	MOVE	A,[4400200000]	;enable for interrupts on parity errors, receiving
	CALLI	A,400025	;INTENB.	mail, and pdl ov
	MOVEI	A,200000
	CALLI	A,400033	;INTGEN.  generate a pdl ov int to set the job name
	MOVE	A,NBRFLR	;get code indicating number of other filers
	JRST	.+2(A)
	UEXIT	4	;	;ONE OTHER FILER ALREADY EXISTED
	UERROR	10	;	;TWO OR MORE OTHER FILERS ALREADY EXISTED

IFN TTY12    <INIT 17,411	;grab AP news line, take error return if not avail
	      SIXBIT /TTY12/>
IFN TTY+DISK <INIT 17,1     >
IFN TTY      <SIXBIT /TTY/  >
IFN DISK     <SIXBIT /DSK/  >
	IBUF
	UBIGERR	14	;	;INIT FAILED ON TTY12

	MOVE	A,IBUF+1	;make byte pointer right size (7 bits--not 36)
	TLZ	A,7700
	TLO	A,700
	MOVEM	A,IBUF+1

	MOVEI	B,TTYBUF	;set up 2 buffers for TTY12 at TTYBUF
	EXCH	B,JOBFF
	INBUF	17,2
	MOVEM	B,JOBFF		;restore old value of JOBFF

	MOVE	BPTR,[POINT 7,BUF-1,35]	;set up byte ptr to buffer to hold 1st new story
;Read in last part of last story.

	OPEN	0,DSK17		;prepare to open NEWS file
	UBIGERR	20	;	;OPEN FAILED ON DSK
	SETZM	NEWSF+3
	LOOKUP	0,NEWSF
	UBIGERR	22	;	;LOOKUP FAILED ON NEWS FILE
	PUSHJ	P,GROW		;expand to full core size
	OPEN	1,DSK17		;prepare to open INDEX file
	UBIGERR	24	;	;OPEN FAILED ON DSK
	SETZM	INDEXF+3
	LOOKUP	1,INDEXF
	UBIGERR	30	;	;LOOKUP FAILED ON INDEX FILE
	IN	1,XCMD		;read in index information
	JRST	.+2
	UBIGERR	34	;	;IN UUO FAILED ON READING IN INDEX FILE
	RELEAS	1,		;INDEX file
	MOVE	UNDUN,INDEX	;load 3 special pointers into ACs
	MOVE	NEW,INDEX+1
	MOVE	OLD,INDEX+2
	HLRZ	A,INDEX+1(NEW)	;get record number of NEW area
	HRRZ	B,INDEX+1(NEW)	;get displacement of NEW area
	PUSHJ	P,SHRINK	;minimize core size
	MOVN	B,B		;make displacement negative
	ASH	B,-13		;right-adjust it
	SUB	BPTR,B		;set up byte pointer to place for next new story
	HRLM	B,CMD		;store length for reading/writing last story
	USETI	0,(A)		;select record in NEWS file
	IN	0,CMD		;read in last part of last story in NEWS file
	JRST	.+2
	UBIGERR	40	;	;IN UUO FAILED ON READING FROM NEWS FILE
	RELEAS	0,
	IN	17,
	JRST	.+2
	UBIGERR	104	;	;IN UUO FAILED TO GET FIRST AP BUFFER
	MOVE	BCNT,IBUF+2
;Search for beginning of story.  Then collect entire story.

GETNEW:	MOVE	STORY,BPTR	;save byte pointer to beginning of next story
GETNE1:	HRRZM	BPTR,HOTLTR+1	;save ptr for sending mail to hot lines
	AOS	HOTLTR+1	;(bptr points to word before first word of story)
	SETZM	1(BPTR)		;zero out first word of ltr so HOT won't get garbage at end of story
RESTRT:	PUSHJ	P,GETCH		;get next char
	CAIE	CHAR,"a"	;LOOK FOR SEQ NBR LIKE "a123"
	JRST	RESTRT
	MOVEI	CNT,3		;got "a". prepare to look for 3 digits after it
	MOVE	A,[POINT 7,SAVEDG]
	MOVEM	A,SPBPTR
	SETZ	AC1,		;AC1 will hold the calculated SEQ NBR
NEXTDG:	PUSHJ	P,GETCH
	CAIG	CHAR,"9"	;is character a digit?
	CAIGE	CHAR,"0"
	JRST	RESTRT		;character wasn't a digit.  start over
	IDPB	CHAR,SPBPTR	;save sequence number of story
	IMULI	AC1,=10		;MULTIPLY OLD SUM BY =10
	ADDI	AC1,-60(CHAR)	;ADD IN NEW DIGIT
	SOJG	CNT,NEXTDG	;got all 3 digits?
	PUSHJ	P,GETCH		;yes.  get next char
IFN TTY12 <
	CAIE	CHAR,LF		;is it a LF?
>
IFN TTY+DISK <
	CAIE	CHAR,CR
>
	JRST	RESTRT		;no.  start over
	MOVEM	AC1,SEQNBR	;SAVE SEQ NBR
	SUBI	BPTR,1
	SETZ	A,
	MOVEI	B,=10
	IDPB	A,BPTR
	SOJG	B,.-1
	PUSHJ	P,SNDHOT
	HRRZM	BPTR,HOTLTR+1
	SOS	HOTLTR+1
FINDCR:	PUSHJ	P,GETCH		;get next char
IFN TTY+DISK <JRST FINDLF>
	SETZ	A,
	DPB	A,BPTR
	CAIE	CHAR,CR		;is it a CR?
	JRST	FINDCR		;no.  keep reading until found CR
	PUSHJ	P,GETCH
FINDLF:	MOVE	BPTR,STORY
	CAIE	CHAR,LF
	JRST	GETNE1		;NO LF FOLLOWING CR AFTER czzcfwwfqrrp.
;Look for end of story.

	ADDI	BPTR,1
	MOVE	A,SAVEDG
	MOVEM	A,(BPTR)
	HRRZM	BPTR,HOTLTR+1
	CALLI	A,400072	;DSKTIM get time when beginning of story came in
	MOVEM	A,BEGTIM	;	and save it
	LDB	B,[POINT 11,A,23];pick up time
	MOVEI	C," "
	IDPB	C,BPTR
	IDIVI	B,=60
	PUSH	P,C
	PUSHJ	P,PUT2DG	;put hour into story
	POP	P,B
	PUSHJ	P,PUT2DG	;put minutes
	MOVEI	C,"p"
	IDPB	C,BPTR
	MOVEI	C,"t"
	IDPB	C,BPTR
	MOVEI	C," "
	IDPB	C,BPTR
	ANDI	A,7777		;get day
	IDIVI	A,=31
	PUSH	P,B
	IDIVI	A,=12
	ADDI	B,1
	PUSHJ	P,PUT2DG	;put month into story
	MOVEI	C,"-"
	IDPB	C,BPTR
	POP	P,B
	ADDI	B,1
	PUSHJ	P,PUT2DG	;put day
	MOVEI	C,CR
	IDPB	C,BPTR
	MOVEI	C,LF
	IDPB	C,BPTR

	MOVEI	CNT,2		;prepare to look for 3 LFs at end of story
NEXTCH:	PUSHJ	P,GETCH		;get next char
	CAIE	CHAR,LF		;is char a LF?
	MOVEI	CNT,3		;no.  reset LF counter
	SOJGE	CNT,NEXTCH	;if haven't found all 4 LFs, go get more text

FNDEND:	CALLI	A,400072	;DSKTIM get time end of story came in
	LDB	B,[POINT 11,A,23]
	LDB	C,[POINT 11,BEGTIM,23]
	SUBM	B,C
	JUMPGE	C,.+2
	ADDI	C,=24*=60	;day changed while story was coming in
	MOVEM	C,DELAY#	;SAVE LENGTH OF TIME STORY TOOK TO COME IN
;Prepare to write out newly read story.

	SETZM	LNKSIN		;set flag to indicate LINKS file hasn't been read in
	SETZM	DICREC		;indicate that no dictionary record is in core
	OUTSTR	[ASCIZ /END /]
DEP0:	IDPB	FLG,BPTR	;right half of AC FLG is always zero
	TLNE	BPTR,760000	;check if at end of word (in story buffer)
	JRST	DEP0
	PUSHJ	P,SNDHOT	;send out last part of story to hot lines
	HRRZ	SIZE,STORY	;compute size (actually negative of size) of story
	HRRZ	A,BPTR		;	by subtracting pointer to last word from
	SUB	SIZE,A		;	pointer to word just before first word
	MOVEI	TXTLEN,BUF-1	;check if story ends on record
	SUB	TXTLEN,A
	TRNE	TXTLEN,177
	JRST	NOTREC
	SETZM	1(BPTR)		;story ends on record.  add one word of zeroes to it
	SUBI	SIZE,1		;increase size by 1
	ADDI	BPTR,1		;increment byte pointer
	SUBI	TXTLEN,1	;increment text length count
NOTREC:	HRLM	TXTLEN,CMD	;store size of story (negated) in dump mode command
	SETOM	BUSY#		;turn on BUSY flag
AGAIN2:	OPEN	2,DSK17		;prepare to create new INDEX file
	UBIGERR	114	;	;OPEN FAILED ON DSK
	SETZM	INDEXF+1
	SETZM	INDEXF+2
	SETZM	INDEXF+3
	ENTER	2,INDEXF	;create new INDEX file
	JRST	[RELEAS	2,
		 MOVEI	A,1
		 CALLI	A,31	;SLEEP
		 JRST	AGAIN2]
	PUSHJ	P,GROW		;expand to full core size
	OPEN	1,DSK17		;prepare to open INDEX file
	UBIGERR	120	;	;OPEN FAILED ON DSK
	SETZM	INDEXF+3
	LOOKUP	1,INDEXF	;INDEX file
	UBIGERR	124	;	;LOOKUP FAILED ON INDEX FILE
	IN	1,XCMD		;read in entire INDEX file
	JRST	.+2
	UBIGERR	130	;	;IN UUO FAILED TO READ IN INDEX FILE 
	RELEAS	1,		;old INDEX file
	MOVE	UNDUN,INDEX	;move special pointers into ACs
	MOVE	NEW,INDEX+1
	MOVE	OLD,INDEX+2
	MOVE	FST,INDEX+1(NEW);get pointer to beginning of area for NEW story
	MOVE	NXT,FST
	ASH	SIZE,13		;move size left to correct field
	SUB	NXT,SIZE	;calculate first word beyond end of story in NEWS
;See how many (if any) old stories must be deleted to fit the new story in.

TRY:	CAMLE	FST,INDEX+1(OLD);check if NEW is below OLD (thus at bottom)
	JRST	ATBOTM
	CAMG	NXT,INDEX+1(OLD);check if NEW story runs over OLD story
	JRST	INSERT		;it doesn't.  write it out
	PUSHJ	P,DELOLD	;it does.  delete an OLD story
	JRST	TRY
ATBOTM:	CAMG	NXT,[XWD RECLMT,0];does new story fit in allowable file size?
	JRST	INSERT		;yes. write it out
	MOVSI	A,'SPL'
	MOVEM	A,SWAPBK+1
	MOVEI	A,SWAPBK
	CALLI	A,400004	;SWAP.  run SPL on another job
	MOVE	A,[SIXBIT /COUNT/]
	MOVEM	A,SWAPBK+1
	MOVEI	A,SWAPBK
	CALLI	A,400004	;SWAP.  run COUNT on another job
	MOVEM	FST,INDEX+3	;no. store ptr to bottom of the NEWS file
	MOVN	NXT,TXTLEN	;prepare to put new story at front of NEWS file
	ADDI	NXT,200
	ASH	NXT,13
	MOVE	FST,SIZE
	ADD	FST,NXT
	MOVEM	FST,INDEX+1(NEW)
NEXT:	CAMG	NXT,INDEX+1(OLD);check if NEW story runs over OLD one
	JRST	INSERT		;it fits.  write it out
	PUSHJ	P,DELOLD	;it doesn't fit.  delete one OLD story
	JRST	NEXT
;Update INDEX file.

INSERT:	MOVE	A,SEQNBR	;retrieve seq nbr
	HRRZM	A,INDEX+2(NEW)	;put the seq nbr into INDEX entry for this story
	ADDI	NEW,XSIZE	;get index pointer for next NEW area
	CAIL	NEW,XLEN
	MOVEI	NEW,SPECS
	CAMN	NEW,OLD		;is NEW index area same as OLD index area?
	PUSHJ	P,DELOLD	;yes, as usual, delete one OLD story
	MOVEM	NXT,INDEX+1(NEW);store rec nbr/displ in new NEW index entry
	HLLZ	NXT,NXT		;zero out displacement part of pointer (leaving only rec.nbr.)
INS2:	HLLZ	A,INDEX+1(OLD)	;get number of record in which OLD story begins
	CAME	NXT,A		;see if new story ends in this same record
	JRST	INS1		;it doesn't
	PUSHJ	P,DELOLD	;it does.  delete one OLD story and
	JRST	INS2		;	check next OLD story
INS1:	SKIPE	DICREC		;has any of the dictionary been read in?
	OUT	3,DCMD		;yes.  write out the new version of the record in core
	JRST	.+2
	UBIGERR	134	;	;OUT UUO FAILED TO WRITE FINAL IN CORE REC OF DICT
	SKIPN	LNKSIN		;has the LINKS file been read in?
	JRST	NOLNKS		;no
	OPEN	4,DSK17		;yes.  write out the new version of LINKS
	UBIGERR	140	;	;OPEN FAILED ON DSK
	SETZM	LINKSF+1
	SETZM	LINKSF+2
	SETZM	LINKSF+3
	ENTER	4,LINKSF
	UBIGERR	144	;	;ENTER FAILED ON LINKS FILE
	OUT	4,LCMD
	JRST	.+2
	UBIGERR	150	;	;OUT UUO FAILED TO WRITE OUT LINKS FILE
	RELEAS	4,		;new LINKS file
NOLNKS:	RELEAS	3,		;new DICT file
	MOVEM	NEW,INDEX+1	;put special pointers back into index array
	MOVEM	OLD,INDEX+2
	OUT	2,XCMD		;write out index information
	JRST	.+2
	UBIGERR	154	;	;OUT UUO FAILED TO WRITE OUT INDEX FILE
;Write out new story.

AGAIN1:	OPEN	0,DSK17		;prepare to open NEWS file
	UBIGERR	160	;	;OPEN FAILED ON DSK
	SETZM	NEWSF+3
	LOOKUP	0,NEWSF		;NEWS file (open sesame)
	UBIGERR	164	;	;LOOKUP FAILED ON NEWS FILE
	SETZM	NEWSF+3
	ENTER	0,NEWSF		;NEWS file again (open for updating)
	JRST	[RELEAS	0,
		 MOVEI	A,1
		 CALLI	A,31	;SLEEP
		 JRST	AGAIN1]
 	HLRM	FST,.+1		;store record number in USETO instr.
	USETO	0.0-0		;select appropriate record for writing out new story
	OUT	0,CMD		;write it out!
	JRST	.+2
	UBIGERR	170	;	;OUT UUO FAILED TO WRITE OUT STORY ON NEWS FILE
	RELEAS	2,
	RELEAS	0,		;close updated NEWS file
	PUSHJ	P,SHRINK	;minimize core size
	MOVE	A,[SIXBIT /[DOER]/];see if a DOER job exists
	CALLI	A,400043	;NAMEIN
	CAIE	A,1		;either no or multiple DOERs exist
	JRST	F1		;one (or more!) DOERs exist
	MOVE	B,[SIXBIT /DOER/];DOER does not already exist so start one up
	MOVEM	B,SWAPBK+1
	MOVEI	B,SWAPBK
	CALLI	B,400004	;SWAP

;move last record of text in story buffer to top of buffer
F1:
;	MOVE	B,DELAY
;	CAILE	B,=22
;	UERROR	400(B)	;	;STORY TOOK MORE THAN 22 MINUTES TO COME IN
	SETZM	BUSY
	SKIPE	GODOWN		;should we go away now?
	JRST	GOAWAY		;YES
	MOVN	TXTLEN,TXTLEN	;no
	TRZ	TXTLEN,177
	CAIN	TXTLEN,0
	JRST	GETNEW
	SUB	BPTR,TXTLEN
	MOVEI	A,BUF
	HRLI	A,BUF(TXTLEN)
	BLT	A,(BPTR)
	JRST	GETNEW		;get next AP story
;UUCODE

ECMD:	IOWD	1,BUF
	0
EMSG:	ASCIZ	/FILER error #/]
ELEN←←.-EMSG

UUCODE:	0
	MOVEI	A,DYING
	MOVEM	A,HOTLTR+1
	PUSHJ	P,SNDHOT
	HRRZ	A,40		;get error number
	MOVE	BPTR,[POINT 7,D]
	SETZ	D,
	PUSHJ	P,NXTDG
	SETO	A,
	GETLIN	A
	AOJE	A,DET
	HLRZ	A,40
	CAIN	A,(<UBIGERR>)
	OUTSTR	[ASCIZ/SUPER /]
	CAIE	A,(<UEXIT>)	;is this a horrendous error?
	OUTSTR	[ASCIZ/HORRENDOUS /]	;yes
	OUTSTR	EMSG
	OUTSTR	D
	CALLI	1,12		;EXIT
	JRST	@UUCODE

DET:	CALLI	0		;RESET
	HLRZ	A,40
	CAIE	A,(<UEXIT>)	;is this a horrendous error?
	OPEN	1,DSK17		;yes.  write message in error file
	EXIT			;no. just exit
	CAIE	A,(<UBIGERR>)	;is this a super horrendous error?
	JRST	DET1		;no
	CALLI	A,400072	;yes.  DSKTIM.  do a wakeme for 30 minutes later
	LDB	B,[POINT 11,A,23];pick up time
	ANDI	A,7777		;zero out time leaving date
	ADDI	B,=30		;put 30 minute hold on [-AP-]
	CAIGE	B,=24*=60	;next day?
	JRST	DET2		;no
	ADDI	A,1		;yes
	SUBI	B,=24*=60
DET2:	HRL	B,A		;put <date>,,<time> in B
	MOVEM	B,WAKEBK+2
	MOVEI	B,WAKEBK
	CALLI	B,400061	;WAKEME in 30 minutes
	JFCL			;ignore error return

DET1:	SETZM	ERRORF+3
	LOOKUP	1,ERRORF
	SETZM	ERRORF+3	;lookup failed.  pretend file there with 0 words
	HLRE	A,ERRORF+3	;pick up word count of error file
	SETZM	ERRORF+3
	ENTER	1,ERRORF
	CALLI	12
	DPB	A,[POINT 7,ECMD,17];put -(word count mod 200) into dump mode command
	MOVN	A,A		;make word count positive
	LDB	B,[POINT 11,A,28];get record part of count
	ANDI	A,177		;get remainder
	JUMPE	A,PUTERR	;if no remainder, then dont read in anything
	USETI	1,1(B)
	IN	1,ECMD
	JRST	.+2
	CALLI	12
PUTERR:	MOVEI	C,BUF(A)
	HRLI	C,EMSG
	BLT	C,BUF+ELEN-1(A)	;put error message into block to be output
	MOVEM	D,BUF+ELEN(A)	;put ASCIZ error number into block
	MOVE	C,CRLF
	MOVEM	C,BUF+ELEN+1(A)	;put crlf after error number
	MOVNI	A,ELEN+2(A)	;calculate number of words to be written out
	HRLM	A,ECMD		; and put it negated into dump mode command
	USETO	1,1(B)
	OUTPUT	1,ECMD
	CALLI	12		;EXIT
;GETCH   NXTDG   PUT2DG

GETCH:	SOJGE	BCNT,LOADCH	;any chars in AP buffer?
	PUSH	P,(BPTR)	;no.  save last word of AP chars
	SETZM	(BPTR)		;then zero the word to ensure zero word at
	PUSHJ	P,SNDHOT	;	end of letter
	HRRZM	BPTR,HOTLTR+1	;set up pointer for sending letter NEXT time
	POP	P,(BPTR)	;restore last word of AP chars
	IN	17,		;get some more news
	JRST	GETCH1
IFN TTY12<UBIGERR 174>	;	;IN UUO FAILED WHEN READING FROM TTY12
IFN TTY+DISK <
	HRRZ	A,(P)
	CAIE	A,NEXTCH+1
	UBIGERR	176	;	;WHO KNOWS WHAT EVIL LURKS IN THE MINDS OF MEN
	SUB	P,[1,,1]
	JRST	FNDEND
>
GETCH1:	HRRZ	A,BPTR
	CAIL	A,BUF+BLEN-200
	JRST	BFOVFL		;STORY BUFFER OVERFLOW
	MOVE	BCNT,IBUF+2	;get byte count
	SOJL	BCNT,GETCH+1	;decrement byte count
LOADCH:	ILDB	CHAR,IBUF+1	;get a char
IFN TTY12<
	TRZE	CHAR,100	;check and mask out 100 bit of incoming AP char
	UERROR	204	;	;100 BIT OF AP CHAR WAS ON
	ADD	CHAR,SHIFT	;SHIFT contains either 100 (octal) or zero
	XCT	CONVRT(CHAR)
>
IFN TTY+DISK <JUMPE CHAR,GETCH>
CHAROK:	IDPB	CHAR,BPTR
	POPJ	P,		;return
BFOVFL:	MOVE	P,[IOWD PDLEN,PDLIST]
	MOVE	BPTR,STORY	;reset byte ptr to beginning of buffer
	JRST	GETNE1		;go look for beginning of story

NXTDG:	IDIVI	A,=8		;convert number in A to octal ASCII string
	PUSH	P,B
	SKIPE	A
	PUSHJ	P,NXTDG
	POP	P,A
	ADDI	A,60
	IDPB	A,BPTR
	POPJ	P,

PUT2DG:	IDIVI	B,=10
	ADDI	B,"0"
	IDPB	B,BPTR
	ADDI	C,"0"
	IDPB	C,BPTR
	POPJ	P,
;DELOLD  GROW    SHRINK

DELOLD:	HLRZ	SLOT,INDEX(OLD)	;get the back ptr from the index entry of OLD
	OUTSTR	[ASCIZ /DELOLD /]
	JUMPE	SLOT,DEL5	;if the back ptr is null, there are no slots to free up
	SKIPE	LNKSIN		;has LINKS been read in already for this story?
	JRST	DEL0		;yes.
	SETOM	LNKSIN		;no.  set flag to indicate it has now and
	OPEN	4,DSK17		;	read in LINKS
	UBIGERR	220	;	;OPEN FAILED ON DSK
	SETZM	LINKSF+3
	LOOKUP	4,LINKSF
	UBIGERR	224	;	;LOOKUP FAILED ON LINKS FILE
	IN	4,LCMD
	JRST	.+2
	UBIGERR	230	;	;IN UUO FAILED TO READ IN LINKS FILE
	RELEAS	4,
DEL0:	HRRZ	C,LINKS+1(SLOT)	;has this link already been freed up?
	JUMPE	C,DEL5		; (zero means yes)
DEL1:	HLRZ	A,LINKS(SLOT)	;get forward ptr to same word, different story
	HRRE	B,LINKS(SLOT)	;get back ptr to same word, different story
	JUMPE	A,DEL2		;is forward ptr null?
	HRRM	B,LINKS(A)	;no.  store new back ptr in slot specified by forward ptr
DEL2:	JUMPL	B,DEL3		;does back ptr point into dictionary?
	HRLM	A,LINKS(B)	;no.  store new forward ptr in slot specified by back ptr
	JRST	DEL4
DEL3:	MOVN	B,B		;back ptr points into dictionary.  make the ptr positive
	MOVE	C,B
	ASH	C,-7		;get the part of the dict ptr indicating the dict record
	ADDI	C,1
	CAMN	C,DICREC	;is the correct dictionary record already in core?
	JRST	DEL6		;yes
	SKIPE	DICREC		;no.  is any record in core?
	JRST	DEL7		;yes
AGAIN3:	OPEN	3,DSK17		;no.  open the DICT file in Read Alter mode
	UBIGERR	234	;	;OPEN FAILED ON DSK
	SETZM	DICTF+3
	LOOKUP	3,DICTF
	JRST	[PAUSE3:	RELEAS 3,
				MOVEI	D,1
				CALLI	D,31	;SLEEP
				JRST	AGAIN3]
	SETZM	DICTF+3
	ENTER	3,DICTF
	JRST	PAUSE3
	JRST	DEL8
DEL7:	OUT	3,DCMD		;write out the record that is in core
	JRST	.+2
	UBIGERR	240	;	;OUT UUO FAILED TO WRITE OUT RECORD OF DICT FILE
DEL8:	MOVEM	C,DICREC	;save the number of the new record being read in
	USETI	3,(C)		;select the record needed in core
	IN	3,DCMD		;read in the new record
	JRST	.+2
	UBIGERR	244	;	;IN UUO FAILED TO READ IN RECORD OF DICT FILE
	USETO	3,(C)		;select the same record for writing it back out later
DEL6:	TRZ	B,777600	;mask out all but the displ of the address of the dict entry
	HRRM	A,DICT+1(B)	;store, in the dictionary entry, a new ptr into LINKS
DEL4:	MOVE	A,LINKS		;return the slot being deleted to the
	MOVEM	A,LINKS(SLOT)	;	free slot list
	MOVEM	SLOT,LINKS	;update the header for the free slot list
	HLLZS	LINKS+1(SLOT)	;zero field to indicate links have been fixed
	HLRZ	SLOT,LINKS+1(SLOT);get the ptr to the next word (slot) for the same story
	JUMPN	SLOT,DEL1	;if it's not null, go back and delete that slot

DEL5:	HRRE	A,INDEX(OLD)	;does story being deleted have a follow up?
	JUMPLE	A,DEL10		; LE means no
	HRRZS	INDEX+2(A)	;yes.  make first follow up the new original
	SKIPA	B,A
DEL9:	HRLM	A,INDEX+2(B)	;store back ptr to new original
	HRRE	B,INDEX(B)	;does this story itself have a follow up?
	JUMPG	B,DEL9		; G means yes.

DEL10:	SETZM	INDEX(OLD)	;clear back ptr and link of OLD INDEX entry
	SETZM	INDEX+2(OLD)	;clear follow-up back ptr & seq nbr
	ADDI	OLD,XSIZE	;adjust OLD to the next INDEX entry
	CAIL	OLD,XLEN
	MOVEI	OLD,SPECS
	POPJ	P,

GROW:
IFE DEBUG <
	PUSH	P,A		;save this AC
	MOVEI	A,BIG
	CALLI	A,11		;CORE.  expand to include DICT and LINKS arrays
	UBIGERR	246	;	;CORE UUO FAILED
	POP	P,A		;restore the AC
>
	POPJ	P,

SHRINK:
IFE DEBUG <
	PUSH	P,A		;save this AC
	MOVEI	A,SMALL
	CALLI	A,11		;CORE. reduce size, eliminating room for DICT/LINKS
	UBIGERR	247	;	;CORE UUO FAILED
	POP	P,A		;restore the AC
>
	POPJ	P,
;CHGNAM  PROCRQ

;interrupt level routine to set the job name
CHGNAM:	SETZ	A,			;zero out own job name
	CALLI	A,400002		;SETNAM
	SETOM	NBRFLR			;initialize indicator to one other filer
	MOVE	A,WAKEBK		;get filer's name from wakeme block
	CALLI	A,400043		;NAMEIN
	JRST	.+2			;zero or multiple filers exist
	CALLI	400024			;DISMIS.  one other filer exists
	SETZM	NBRFLR			;set indicator to multiple filers
	CAIE	A,1			;check error code of NAMEIN
	CALLI	400024			;DISMIS.  two or more other filers exist
	AOS	NBRFLR			;set indicator to no other filers
	MOVE	A,WAKEBK		;change job name
	CALLI	A,400002		;SETNAM
	MOVEI	A,200000
	CALLI	A,400027		;INTACM.  disable for further pdl ov ints
	CALLI	400024			;DISMIS

;process a request for the hot line
PROCRQ:	SKIPE	GODOWN
	CALLI	400024		;DISMIS
	JRST@	2,[.+1]		;get out of USER-IOT mode
	WRCV	INLTR
	MOVS	A,INLTR
	CAIE	A,'HOT'		;did letter come from HOT?
	JRST	NOTHOT		;no
	OUTSTR	[ASCIZ /HOTRQ /]
	MOVEI	E,1		;yes
	MOVE	A,INLTR+1	;get job number of job requesting hot line
	JUMPLE	A,NOJBNO	;make sure job nbr is positive
	CAILE	A,=35
	SETZ	E,		;if job number is greater than 35, then its bit is in 1st word
	CAILE	A,=71		;make sure job nbr is less than 72
	JRST	NOJBNO		;job number is too big
	MOVEI	C,1		;turn on the low order bit of AC
	ROT	C,(A)		;rotate bit into correct position
	IORM	C,WHOHOT(E)	;turn on hot line bit for job sending request
NOJBNO:	CALLI	400024		;DISMIS

NOTHOT:	CAME	A,[645500552371]
	CALLI	400024		;DISMIS
	SETOM	GODOWN#
	SKIPE	BUSY		;can we quit now?
	CALLI	400024		;no. DISMIS
	CALLI	400034		;yes. UWAIT.
	CALLI	400035		;DEBREAK
GOAWAY:	MOVEI	A,INLTR+1	;get address of special message
	MOVEM	A,HOTLTR+1	;send out message to hot line listeners
	PUSHJ	P,SNDHOT
	UEXIT	250	;	;MANUAL DEATH
;INTRPT  SNDHOT

;interrupt level module
INTRPT:	MOVE	A,JOBCNI	;get bit causing interrupt
	JFFO	A,.+1
	CAIN	A+1,6		;did a letter come in?
	JRST	PROCRQ		;yes.  process it
	CAIN	A+1,=19		;no.  is this interrupt to set filer's job name?
	JRST	CHGNAM		;yes.  do it
	MOVSI	C,400		;no.  disable for all but parity error interrupts
	CALLI	C,400025	;INTENB
	MOVEM	A+1,SVINTR#	;save indicator of the cause of the interrupt
	CALLI	400034		;UWAIT
	JRST@	2,[.+1]		;get out of user-iot
	CALLI	400035		;DEBREAK
	MOVE	A,SVINTR
	CAIE	A,=9		;was this interrupt for a parity error?
	UERROR	210	;	;UNKNOWN INTERRUPT OCCURRED IN FILER
	UEXIT	214	;	;PARITY ERROR IN FILER

;send out latest buffer to all hot line users
SNDHOT:
IFN DISK <POPJ P,>
	SKIPN	@HOTLTR+1	;if letter to be sent starts out with a word
	POPJ	P,		;	of zeroes, there is no use sending it
	MOVEI	E,1
HOT4:	MOVE	A,WHOHOT(E)
	JRST	HOT1
HOT2:	SUB	A+1,EXCESS(E)
	MOVN	A+1,A+1
	MOVEM	A+1,HOTLTR	;store job number of addressee of hot line letter
	MOVEI	C,1
	ROT	C,(A+1)		;rotate to the bit for this job
	MAIL	5,HOTLTR	;send the hot line letter
	JRST	TRY2ND
	JRST	HOT3
REMHOT:	ANDCAM	C,WHOHOT(E)	;failed to send mail.  remove jobnbr from mailing list
HOT3:	ANDCM	A,C		;turn off this guy's bit in the AC (A)
HOT1:	JFFO	A,HOT2
	SOJGE	E,HOT4
	POPJ	P,
TRY2ND:	MOVEI	B,1		;failed to send mail on first try.  try a 2nd time.
	CALLI	B,31		;SLEEP
	MAIL	5,HOTLTR
	JRST	TRY3RD
	JRST	HOT3
	JRST	REMHOT
TRY3RD:	CALLI	B,31		;SLEEP.  try a 3rd time (last chance)
	MAIL	5,HOTLTR
	JRST	REMHOT
	JRST	HOT3
	JRST	REMHOT
CONVRT:	JRST	GETCH		;0: tape feed
	MOVEI	CHAR,"e"	;1
	MOVEI	CHAR,LF		;2: elevate→line feed
	MOVEI	CHAR,"a"	;3
	JRST	CKPARA		;4: space.  make into 4 spaces if after LF
	MOVEI	CHAR,"s"	;5
	MOVEI	CHAR,"i"	;6
	MOVEI	CHAR,"u"	;7
	MOVEI	CHAR,CR		;10: carriage return
	MOVEI	CHAR,"d"	;11
	MOVEI	CHAR,"r"	;12
	MOVEI	CHAR,"j"	;13
	MOVEI	CHAR,"n"	;14
	MOVEI	CHAR,"f"	;15
	MOVEI	CHAR,"c"	;16
	MOVEI	CHAR,"k"	;17
	MOVEI	CHAR,"t"	;20
	MOVEI	CHAR,"z"	;21
	MOVEI	CHAR,"l"	;22
	MOVEI	CHAR,"w"	;23
	MOVEI	CHAR,"h"	;24
	MOVEI	CHAR,"y"	;25
	MOVEI	CHAR,"p"	;26
	MOVEI	CHAR,"q"	;27
	MOVEI	CHAR,"o"	;30
	MOVEI	CHAR,"b"	;31
	MOVEI	CHAR,"g"	;32
	JRST	SETSHF		;33: shift
	MOVEI	CHAR,"m"	;34
	MOVEI	CHAR,"x"	;35
	MOVEI	CHAR,"v"	;36
	JRST	CLRSHF		;37: unshift

	JRST	CKPARA		;40: thin space→space
	MOVEI	CHAR,"3"	;41
	MOVEI	CHAR,LF		;42: paper feed→line feed
	MOVEI	CHAR,"$"	;43
	JRST	CKPARA		;44: add thin space→space
	JRST	CKPARA		;45: em space→space
	MOVEI	CHAR,"8"	;46
	MOVEI	CHAR,"7"	;47
	MOVEI	CHAR,"'"	;50
	MOVEI	CHAR,"-"	;51
	MOVEI	CHAR,"4"	;52
	JRST	GETCH		;53: bell
	MOVEI	CHAR,","	;54: comma
	JRST	GETCH		;55: undefined
	JRST	CKPARA		;56: en space→space
	JRST	GETCH		;57: quad right
	MOVEI	CHAR,"5"	;60
	MOVEI	CHAR,")"	;61
	JRST	CKPARA		;62: em space→space
	MOVEI	CHAR,"2"	;63
	JRST	GETCH		;64: em leader
	MOVEI	CHAR,"6"	;65
	MOVEI	CHAR,"0"	;66
	JRST	GETCH		;67: en leader
	MOVEI	CHAR,"9"	;70
	JRST	GETCH		;71: upper rail
	MOVEI	CHAR,";"	;72
	JRST	GETCH		;73: lower rail
	MOVEI	CHAR,"."	;74: period
	MOVEI	CHAR,"1"	;75
	JRST	GETCH		;76: undefined
	JRST	GETCH		;77: rub out
UPPER:	JRST	GETCH		;0: tape feed
	MOVEI	CHAR,"E"	;1
	MOVEI	CHAR,LF		;2: elevate→line feed
	MOVEI	CHAR,"A"	;3
	JRST	CKPARA		;4: space.  make into 4 spaces if after LF
	MOVEI	CHAR,"S"	;5
	MOVEI	CHAR,"I"	;6
	MOVEI	CHAR,"U"	;7
	MOVEI	CHAR,CR		;10: carriage return
	MOVEI	CHAR,"D"	;11
	MOVEI	CHAR,"R"	;12
	MOVEI	CHAR,"J"	;13
	MOVEI	CHAR,"N"	;14
	MOVEI	CHAR,"F"	;15
	MOVEI	CHAR,"C"	;16
	MOVEI	CHAR,"K"	;17
	MOVEI	CHAR,"T"	;20
	MOVEI	CHAR,"Z"	;21
	MOVEI	CHAR,"L"	;22
	MOVEI	CHAR,"W"	;23
	MOVEI	CHAR,"H"	;24
	MOVEI	CHAR,"Y"	;25
	MOVEI	CHAR,"P"	;26
	MOVEI	CHAR,"Q"	;27
	MOVEI	CHAR,"O"	;30
	MOVEI	CHAR,"B"	;31
	MOVEI	CHAR,"G"	;32
	JRST	SETSHF		;33: shift
	MOVEI	CHAR,"M"	;34
	MOVEI	CHAR,"X"	;35
	MOVEI	CHAR,"V"	;36
	JRST	CLRSHF		;37: unshift

	JRST	CKPARA		;40: thin space→space
	JRST	SPE3		;41: 3/8
	MOVEI	CHAR,LF		;42: paper feed→line feed
	MOVEI	CHAR,"!"	;43
	JRST	CKPARA		;44: add thin space→space
	JRST	CKPARA		;45: em space→space
	MOVEI	CHAR,"-"	;46
	JRST	SPE7		;47: 7/8
	MOVEI	CHAR,"'"	;50: left quote→right quote (ttys dont have left quote)
	MOVEI	CHAR,"+"	;51
	JRST	SPE4		;52: 1/2
	JRST	GETCH		;53: bell
	MOVEI	CHAR,","	;54: comma
	JRST	GETCH		;55: undefined
	JRST	CKPARA		;56: en space→space
	JRST	GETCH		;57: quad right
	JRST	SPE5		;60: 5/8
	MOVEI	CHAR,"("	;61
	JRST	CKPARA		;62: em space→space
	JRST	SPE2		;63: 1/4
	JRST	GETCH		;64: em leader
	JRST	SPE6		;65: 3/4
	MOVEI	CHAR,"?"	;66
	JRST	GETCH		;67: en leader
	MOVEI	CHAR,"&"	;70
	JRST	GETCH		;71: upper rail
	MOVEI	CHAR,":"	;72
	JRST	GETCH		;73: lower rail
	MOVEI	CHAR,"."	;74: period
	JRST	SPE1		;75: 1/8
	JRST	GETCH		;76: undefined
	JRST	GETCH		;77: rub out
;SETSHF  CLRSHR  SPE1-7  CKPARA

SETSHF:	MOVEI	CHAR,100
	MOVEM	CHAR,SHIFT
	JRST	GETCH
CLRSHF:	SETZM	SHIFT
	JRST	GETCH
SPE1:	MOVEI	CHAR," "
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"1"	;1/8
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"/"
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"8"
	IDPB	CHAR,BPTR
	POPJ	P,
SPE2:	MOVEI	CHAR," "
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"1"	;1/4
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"/"
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"4"
	IDPB	CHAR,BPTR
	POPJ	P,
SPE3:	MOVEI	CHAR," "
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"3"	;3/8
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"/"
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"8"
	IDPB	CHAR,BPTR
	POPJ	P,
SPE4:	MOVEI	CHAR," "
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"1"	;1/2
	IDPB	CHAR,BPTR
 	MOVEI	CHAR,"/"
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"2"
	IDPB	CHAR,BPTR
	POPJ	P,
SPE5:	MOVEI	CHAR," "
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"5"	;5/8
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"/"
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"8"
	IDPB	CHAR,BPTR
	POPJ	P,
SPE6:	MOVEI	CHAR," "
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"3"	;3/4
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"/"
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"4"
	IDPB	CHAR,BPTR
	POPJ	P,
SPE7:	MOVEI	CHAR," "
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"7"	;7/8
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"/"
	IDPB	CHAR,BPTR
	MOVEI	CHAR,"8"
	IDPB	CHAR,BPTR
	POPJ	P,

CKPARA:	MOVEI	CHAR," "
	IDPB	CHAR,BPTR	;deposit at least 1 space
	CAIE	CNT,1		;if the previous char was a LF, CNT will be 1
	POPJ	P,		;not after LF
	IDPB	CHAR,BPTR	;after lf: make space into 4 spaces
	IDPB	CHAR,BPTR
	IDPB	CHAR,BPTR
	POPJ	P,

	VAR
	LIT
SMALL←.				;size of core needed when without LINKS and DICT
INDEX←.				;core is expanded to hold these arrays when
LINKS←.+XLEN			;	they are needed
DICT←LINKS+LLEN
BIG←DICT+DLEN			;size of core needed to hold both LINKS and DICT
IFN DEBUG <BLOCK XLEN+LLEN+DLEN
>

	END	FILER